/**
 * JAVACC DEMO 1.0
 * @copy right apache company All rights reserved. 
 * @Package com.apache.task.api  
 */
package com.apache.task.api;

import com.apache.cache.service.CacheManager;
import com.apache.cache.service.impl.LoadCacheFactory;
import com.apache.database.model.TaskEntity;
import com.apache.rpc.common.RpcUtil;
import com.apache.task.impl.TaskRemoteRunnable;
import com.apache.task.impl.TaskRunnable;
import com.apache.task.impl.TaskSpringRunnable;
import com.apache.task.util.XmlReader;
import com.apache.tools.ConfigUtil;
import com.apache.tools.OsUtils;
import com.apache.tools.StrUtil;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * description:  定时任务启动控制类
 * @author Hou Dayu 创建时间：2016-1-14
 * @Copyright(c)2014:
 */
public class ScheduledExecutor {

	private static ScheduledExecutor instance;
	private int poolNum = 5;
	private ScheduledExecutorService scheduExec;
	private List<TaskEntity> tasks;

	private Map<String, ScheduledFuture> threadMap = new HashMap<String, ScheduledFuture>();

	private String stratWay = "file";//启动方式（file：读本地文件；其他：读数据库）
	private CacheManager cache = LoadCacheFactory.getInstance().getCacheManager("task_timer_map");

	private ScheduledExecutor() {
	}

	/**
	 * description:  创建单实例方法
	 * @return   
	 */
	public static ScheduledExecutor newInstance() {
		return instance;
	}

	/**
	 * description:    开启全部任务
	 */
	public void start() {
		if(stratWay.equalsIgnoreCase("file")){
			getTasks();
			if (StrUtil.isEmpty(tasks))
				return;
			for (TaskEntity task : tasks) {
				if (!task.isOpenStart())
					startTask(task);
			}
		}
	}

	/**
	 * description:    开启全部任务
	 */
	public void initStart() {
		if(stratWay.equalsIgnoreCase("file")) {
			getTasks();
			if (StrUtil.isEmpty(tasks))
				return;
			for (TaskEntity task : tasks) {
				if (task.getTaskStatus() == 1)
					startTask(task);
			}
		}
	}

	/**
	 * description:  开启指定任务
	 */
	public void start(String key) {
		if(stratWay.equalsIgnoreCase("file")) {
			getTasks();
			if (StrUtil.isEmpty(tasks))
				return;
			for (TaskEntity task : tasks) {
				if (task.getTaskKey().equalsIgnoreCase(key)) {
					startTask(task);
					return;
				}
			}
		}else{
			Object obj = getCache().getCacheObjectByKey(key);
			if(null != obj){
				TaskEntity task = (TaskEntity)obj;
				String ip = OsUtils.getLocalIp();
				if (!task.isOpenStart() && ip.equals(task.getServerIp())) {
					startTask(task);
					setCacheTask(task.getTaskKey(),task);
				}
			}
		}
	}

	/**
	 * description:  停止指定任务
	 */
	public void stopTaskByKey(String key) {
		ScheduledFuture sf = threadMap.get(key);
		if (null != sf) {
			sf.cancel(true);
			threadMap.remove(key);
			if(stratWay.equalsIgnoreCase("file")) {
				for (TaskEntity task : tasks) {
					if (task.getTaskKey().equalsIgnoreCase(key)) {
						task.setOpenStart(false);
					}
				}
			}else{
				Object obj = getCache().getCacheObjectByKey(key);
				if(null != obj){
					TaskEntity task = (TaskEntity)obj;
					String ip = OsUtils.getLocalIp();
					if (!task.isOpenStart() && ip.equals(task.getServerIp())) {
						task.setOpenStart(false);
						setCacheTask(task.getTaskKey(),task);
					}
				}
			}
		}
	}

	/**
	 * description:  关闭线程池
	 * @author Hou Dayu
	 * @update 2015-1-23
	 */
	public void stopTasks() {
		scheduExec.shutdown();
		if(stratWay.equalsIgnoreCase("file")) {
			if (!StrUtil.isEmpty(tasks)) {
				tasks.clear();
			}
		}
		threadMap.clear();
		scheduExec = null;
		scheduExec = Executors.newScheduledThreadPool(poolNum);
	}

////////////////////////////////////////////////////////////////////////////////////
	/**
	 * description:    开启全部任务
	 */
	public void startBySysName(String sysName,String ip) {
		List<TaskEntity> list = getTasks(sysName);
		if (StrUtil.isEmpty(list))
			return;
		if(!stratWay.equalsIgnoreCase("file")) {
			for (TaskEntity task : list) {
				if (!task.isOpenStart() && ip.equals(task.getServerIp())) {
					if(!task.isOpenStart()){
						startTask(task);
						setCacheTask(task.getTaskKey(), task);
					}
				}
			}
		}
	}

	/**
	 * description:    开启全部任务
	 */
	public void initStart(String sysName,String ip) {
		List<TaskEntity> list = getTasks(sysName);
		if (StrUtil.isEmpty(list))
			return;
		if(!stratWay.equalsIgnoreCase("file")) {
			for (TaskEntity task : list) {
				if (task.getTaskStatus() == 1 && ip.equals(task.getServerIp())) {
					if(!task.isOpenStart()){
						startTask(task);
						setCacheTask(task.getTaskKey(), task);
					}
				}
			}
		}
	}

	/**
	 * description:  开启指定任务
	 */
	public void start(String sysName,String key,String ip) {
		if(!stratWay.equalsIgnoreCase("file")) {
			Object obj = getCache().getCacheObjectByKey(key);
			if(null != obj){
				TaskEntity task = (TaskEntity)obj;
				if (task.getSysName().equalsIgnoreCase(sysName) && ip.equals(task.getServerIp())) {
					if(!task.isOpenStart()){
						startTask(task);
						setCacheTask(task.getTaskKey(), task);
					}
				}
			}
		}
	}

	/**
	 * description:  停止指定任务
	 */
	public void stopTaskByKey(String sysName,String key,String ip) {
		ScheduledFuture sf = threadMap.get(key);
		if (null != sf) {
			sf.cancel(true);
			threadMap.remove(key);
			if(!stratWay.equalsIgnoreCase("file")) {
				Object obj = getCache().getCacheObjectByKey(key);
				if(null != obj){
					TaskEntity task = (TaskEntity)obj;
					if (task.getSysName().equalsIgnoreCase(sysName) && ip.equals(task.getServerIp())) {
						task.setOpenStart(false);
						setCacheTask(task.getTaskKey(), task);
					}
				}
			}
		}
	}

	/**
	 * description:  关闭线程池
	 * @author Hou Dayu
	 * @update 2015-1-23
	 */
	public void stopTasks(String sysName,String ip) {
		List<TaskEntity> list = getTasks(sysName);
		if (!StrUtil.isEmpty(list)) {
			if(!stratWay.equalsIgnoreCase("file")) {
				for (TaskEntity task : list) {
					ScheduledFuture sf = threadMap.get(task.getTaskKey());
					if (null != sf) {
						sf.cancel(true);
						threadMap.remove(task.getTaskKey());
						task.setOpenStart(false);
						setCacheTask(task.getTaskKey(), task);
					}
				}
				scheduExec.shutdown();
				threadMap.clear();
				scheduExec = null;
				scheduExec = Executors.newScheduledThreadPool(poolNum);
			}
		}
	}

	private void setCacheTask(String key,TaskEntity task){
		cache.createCacheObject(key,task);
	}

	/**
	 * description:  启动定时任务
	 */
	private void startTask(TaskEntity task) {
		long period = 0;// hour + minute + second
		long oneDay = 24 * 60 * 60 * 1000;
		long initDelay = 0;//task.getInitialDelay()
		if (task.getIntervalType() == 1) {//每天定时执行
			String time = XmlReader.newInstance().noZero(task.getHour() + "", 2, "l") + ":";
			time += XmlReader.newInstance().noZero(task.getMinute() + "", 2, "l") + ":";
			time += XmlReader.newInstance().noZero(task.getSecond() + "", 2, "l");
			initDelay = getTimeMillis(time);
			initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;
			period = oneDay;
		} else {
			long timeLong = task.getHour() * 60 * 60 * 1000;
			long minute = task.getMinute() * 60 * 1000;
			long second = task.getSecond() * 1000;
			period = timeLong + minute + second;
		}
		if (!task.isOpenStart()) {
			Runnable runnable = null;
			if (StrUtil.isNull(task.getTaskType())) {
				runnable = new TaskRunnable(task);
			} else if ("spring".equalsIgnoreCase(task.getTaskType())) {
				runnable = new TaskSpringRunnable(task);
			} else if ("remote".equalsIgnoreCase(task.getTaskType())) {
				runnable = new TaskRemoteRunnable(task);
			}
			try {
				ScheduledFuture sf = scheduExec.scheduleAtFixedRate(runnable, initDelay, period,
						TimeUnit.MILLISECONDS);//.SECONDS)
				//scheduExec.scheduleWithFixedDelay(runnable, initDelay, period, TimeUnit.SECONDS)
				threadMap.put(task.getTaskKey(), sf);
				task.setOpenStart(true);
			}catch (Exception e){}
		}
	}

	/**
	 * 获取指定时间对应的毫秒数 
	 * @param time "HH:mm:ss" 
	 * @return 
	 */
	private long getTimeMillis(String time) {
		try {
			DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
			DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");
			Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time);
			return curDate.getTime() - System.currentTimeMillis();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * description:  获取所有任务
	 * @return   
	 * @author Hou Dayu  
	 * @update 2015-1-14
	 */
	public List<TaskEntity> getTasks() {
		if (StrUtil.isEmpty(tasks)) {
			tasks = XmlReader.newInstance().readerConfig();
		}
		return tasks;
	}

	public List<TaskEntity> getTasks(String sysName){
		List<TaskEntity> list =null;
		synchronized (this){
			if(stratWay.equalsIgnoreCase("file")){
				list = getTasks();
			} else {
				list = XmlReader.newInstance().readerDatabase(sysName);
			}
		}
		return list;
	}

	/**
	 * description: 初始化方法
	 * @author Hou Dayu  
	 * @update 2015-1-14
	 */
	public void init() {
		instance = this;
		poolNum = Integer.parseInt(StrUtil.doNull(ConfigUtil.getInstance().getValueByKey("task.pool.number"),"5"));
		scheduExec = Executors.newScheduledThreadPool(poolNum);
		boolean isOpenTimeServer = Boolean.parseBoolean(StrUtil.doNull(RpcUtil.getInstance().getValueByKey("open.task.server.flag"),"false"));
		String isFile = StrUtil.doNull(RpcUtil.getInstance().getValueByKey("read.file.database"),"file");
		if(isOpenTimeServer && stratWay.equalsIgnoreCase(isFile)) {//是否开启定时任务
			initStart();
		}
	}

	/**
	 * description:  销毁方法
	 * @author Hou Dayu  
	 * @update 2015-1-14
	 */
	public void destroy() {
		scheduExec.shutdown();
		scheduExec = null;
		instance = null;
	}


	public String getStratWay() {
		return stratWay;
	}

	public void setStratWay(String stratWay) {
		this.stratWay = stratWay;
	}

	public CacheManager getCache() {
		return cache;
	}

}
